package com.general.client.widgets.checkbox;

import com.general.client.basewidget.BaseWidget;
import com.general.client.bundle.CommonBundle;
import com.general.client.enableable.Enableable;
import com.general.client.error.Error;
import com.general.client.hasinterfaces.HasHint;
import com.general.client.hasinterfaces.HasLabel;
import com.general.client.mandatory.Mandatory;
import com.general.client.modes.HasModes;
import com.general.client.modes.WidgetMode;
import com.general.client.position.Position;
import com.general.client.validator.Validateable;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;

public class Checkbox extends BaseWidget implements HasValue<Boolean>,
		Mandatory, Validateable, HasLabel, HasHint, Enableable, HasModes, Error {

	private static CheckboxUiBinder uiBinder = GWT
			.create(CheckboxUiBinder.class);

	interface CheckboxUiBinder extends UiBinder<Widget, Checkbox> {
	}

	@UiField
	CommonBundle bundle;

	@UiField
	FlowPanel labelContainer;
	@UiField
	Label astrix;
	@UiField
	Label label;

	@UiField
	FlowPanel buttonContainer;
	@UiField
	Anchor buttonView;
	@UiField
	CheckBox button;

	private boolean showLabel = true;
	private Position labelPosition = Position.LEFT;
	private HandlerRegistration addValueChangeHandlerRegistration = null;
	private boolean isMandatory = false;
	private WidgetMode mode = WidgetMode.EDIT;
	private HandlerRegistration onClickSwitchToEditRegistration;
	private HandlerRegistration onBlurSwitchToViewRegistration;
	private String hint;
	private boolean showHint;
	private boolean error;

	public Checkbox() {
		initWidget(uiBinder.createAndBindUi(this));
		setDefaults();
	}

	private void setDefaults() {
		setShowHint(false);
		setShowLabel(true);
		setLabelPosition(Position.LEFT);
		setMode(WidgetMode.EDIT);
		setError(false);
		setMandatory(false);
	}

	@Override
	public HandlerRegistration addValueChangeHandler(
			ValueChangeHandler<Boolean> handler) {
		return button.addValueChangeHandler(handler);
	}

	@Override
	public void setEnabled(boolean enabled) {
		button.setEnabled(enabled);
	}

	@Override
	public boolean isEnabled() {
		return button.isEnabled();
	}

	@Override
	public String getLabel() {
		return label.getText();
	}

	@Override
	public void setLabel(String labelString) {
		label.setText(labelString);
	}

	@Override
	public boolean isShowLabel() {
		return showLabel;
	}

	@Override
	public void setShowLabel(boolean showLabel) {
		this.showLabel = showLabel;
		labelContainer.setVisible(showLabel);
	}

	@Override
	public Position getLabelPosition() {
		return this.labelPosition;
	}

	@Override
	public void setLabelPosition(Position labelPosition) {
		this.labelPosition = labelPosition;
		if (labelPosition.equals(Position.ABOVE)) {
			button.addStyleName(bundle.style().positionAbove());
			buttonView.addStyleName(bundle.style().positionAbove());
		} else if (labelPosition.equals(Position.LEFT)) {
			button.addStyleName(bundle.style().positionLeft());
			buttonView.addStyleName(bundle.style().positionLeft());
		}
	}

	@Override
	public boolean isValid() {
		boolean valid = ((this.isMandatory() && getValue() != true) || !this
				.isMandatory());
		setError(valid);
		return valid;
	}

	@Override
	public void setValidateOnValueChange(boolean validateOnValueChange) {
		if (validateOnValueChange && addValueChangeHandlerRegistration == null) {
			addValueChangeHandlerRegistration = addValueChangeHandler(new ValueChangeHandler<Boolean>() {

				@Override
				public void onValueChange(ValueChangeEvent<Boolean> event) {
					isValid();
				}
			});
		} else if (addValueChangeHandlerRegistration != null) {
			addValueChangeHandlerRegistration.removeHandler();
			addValueChangeHandlerRegistration = null;
		}
	}

	@Override
	public void setMandatory(boolean isMandatory) {
		this.isMandatory = isMandatory;
		astrix.setVisible(isMandatory);
	}

	@Override
	public boolean isMandatory() {
		return isMandatory;
	}

	@Override
	public Boolean getValue() {
		return button.getValue();
	}

	@Override
	public void setValue(Boolean value) {
		button.setValue(value);
		setViewValue(value);
	}

	@Override
	public void setValue(Boolean value, boolean fireEvents) {
		button.setValue(value, fireEvents);
		setViewValue(value);
	}

	private void setViewValue(Boolean value) {
		if (value) {
			buttonView.addStyleName(bundle.style().checkboxViewChecked());
			buttonView.removeStyleName(bundle.style().checkboxViewUnchecked());
		} else {
			buttonView.addStyleName(bundle.style().checkboxViewUnchecked());
			buttonView.removeStyleName(bundle.style().checkboxViewChecked());
		}
	}

	@Override
	public WidgetMode getMode() {
		return this.mode;
	}

	@Override
	public void setMode(WidgetMode mode) {
		this.mode = mode;
		if (mode.equals(WidgetMode.EDIT)) {
			button.setVisible(true);
			buttonView.setVisible(false);
			button.setFocus(true);
		} else {
			setViewValue(getValue());
			buttonView.setVisible(true);
			button.setVisible(false);
		}

	}

	@Override
	public void setOnClickSwitchToEdit(boolean onFocusSwitchToEdit) {
		if (onFocusSwitchToEdit && onClickSwitchToEditRegistration == null) {
			onClickSwitchToEditRegistration = buttonView
					.addClickHandler(new ClickHandler() {

						@Override
						public void onClick(ClickEvent event) {
							if (isEnabled()) {
								setMode(WidgetMode.EDIT);
							}
						}
					});
		} else if (onClickSwitchToEditRegistration != null) {
			onClickSwitchToEditRegistration.removeHandler();
		}
	}

	@Override
	public void setOnBlurSwitchToView(boolean onBlurSwitchToView) {
		if (onBlurSwitchToView && onBlurSwitchToViewRegistration == null) {
			onBlurSwitchToViewRegistration = button
					.addBlurHandler(new BlurHandler() {

						@Override
						public void onBlur(BlurEvent event) {
							setMode(WidgetMode.VIEW);
						}
					});
		} else if (onBlurSwitchToViewRegistration != null) {
			onBlurSwitchToViewRegistration.removeHandler();
		}
	}

	@Override
	public void setHint(String hint) {
		this.hint = hint;
		if (isShowHint()) {
			button.setText(hint);
		} else {
			button.setText("");
		}
	}

	@Override
	public boolean isShowHint() {
		return this.showHint;
	}

	@Override
	public void setShowHint(boolean showHint) {
		this.showHint = showHint;
		setHint(hint);
	}

	@Override
	public boolean isError() {
		return this.error;
	}

	@Override
	public void setError(boolean error) {
		this.error = error;
		if (error) {
			button.addStyleName(bundle.style().error());
			buttonView.addStyleName(bundle.style().error());
		} else {
			button.removeStyleName(bundle.style().error());
			buttonView.removeStyleName(bundle.style().error());
		}
	}

}
